#include "PCResource.h"
#include <unistd.h>


static int thread_func(PCResource *obj);

// 数据解析表 - 前导字符串
static const char *rs_data_header[] = {
    "CPU usage",
    "CPU temp",
    "CPU freq",
    "CPU power",
    "GPU usage",
    "GPU temp",
    "GPU freq",
    "GPU power",
    "RAM usage",
    "RAM use",
    "NET upload speed",
    "NET download speed",
    "GRAM use",
    "GRAM usage",
    "Disk temp",
    "Disk usage",
    "CPU fan speed",
    "GPU fan speed",
    "Time",
    ":",
    "Date",
    "/",
    "/",
    "CPUM",
    "GPUM"
};
// 数据解析表 - 单位
static const char *rs_data_unit[] = {
    "%",
    "C",
    "MHz",
    "W",
    "%",
    "C",
    "MHz",
    "W",
    "%",
    "MB",
    "KB/s",
    "KB/s",
    "MB",
    "%",
    "C",
    "%",
    "RPM",
    "RPM",
    ":",
    "{|}",
    "/",
    "/",
    "{|}",
    "Mod",
    "Mod"
};

/*
  *@brief PCResource构造函数
  *@param ipaddr PC端内网IP地址
  *@param port  端口号
  *@param exit_cb 退出进程回调函数
  */
PCResource::PCResource(string &ipaddr, int port, exit_cb_t exit_cb, mutex &UIMutex)
{
    thread_exit_flag = false;

    gui_opt_t gui_opts;
    gui_opts.exit_cb = exit_cb;

    ip_addr = ipaddr;
    ui_mutex = &UIMutex;

    server_addr.sin_family = AF_INET;                          // IPv4协议
    server_addr.sin_port = htons(port);                        // 端口号
    inet_pton(AF_INET, ip_addr.c_str(), &server_addr.sin_addr); // IP地址

    pc_resource_gui_init(&gui_opts);

    pthread = new std::thread(thread_func, this);           //创建执行线程
}

PCResource::~PCResource()
{
    if (socket_fd > 0)
        close(socket_fd);
    thread_exit_flag = true;
    pthread->join();
    delete pthread;

    pc_resource_gui_release();
}

/*
  *@brief 获取PC硬件信息(由AIDA64发送)
  *@param info 保存信息的字符串(引用)
  *@return  获取成功返回0,失败返回-1
  */
int PCResource::GetData(string &info)
{
    int ret = -1;

    do
    {
        socket_fd = socket(AF_INET, SOCK_STREAM, 0); // 打开socket
        if (socket_fd < 0)
        {
            perror("socket open error");
            break;
        }
        ret = connect(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));     //连接服务器
        if (ret < 0)
        {
            perror("socket connect error");
            break;
        }

        string getUrl = "GET /sse HTTP/1.1\r\nContent-Type=application/json;charset=utf-8\r\n\
                Host: " + ip_addr + "\r\nUser-Agent=Mnipad\r\nConnection: close\r\n\r\n";

        ret = send(socket_fd, getUrl.c_str(), getUrl.length(), 0);      //发送GET请求
        if (ret < 0)
        {
            perror("socket send error");
            break;
        }

        usleep(50000);      //线程休眠等待服务器反应
        char *buf = (char *)malloc(4096);

        ret = recv(socket_fd, buf, 4096, 0);            //接收数据
        if (ret < 0)
        {
            perror("socket recv error");
            break;
        }

        info = string(buf);     //保存数据
        free(buf);
        ret = 0;
    } while (0);

    if(socket_fd >=0 )
    {
        close(socket_fd);
        socket_fd = -1;
    }

    return ret;
}

/*
  *@brief 解析信息数据
  *@param info 保存信息的字符串(引用)
  *@return  PC硬件资源信息
  */
PCResInfo PCResource::AnalyticData(string &info)
{
    size_t dataStart = 0;
    size_t dataEnd = 0;
    string dataStr;
    PCResInfo res_data;
    int data[23] = {0};
    int i;

    // 解析数据
    for (i = 0; i < 23; i++)
    {
        dataStart = info.find(rs_data_header[i], dataEnd) + strlen(rs_data_header[i]); // 寻找前导字符串
        dataEnd = info.find(rs_data_unit[i], dataStart);                      // 寻找单位字符串
        if(dataEnd != string::npos)
        {
            dataStr = info.substr(dataStart, dataEnd - dataStart);

            data[i] = atof(dataStr.c_str()) * 10; // 得到扩大10倍的整型数据
        }
    }

    dataStart = info.find(rs_data_header[i]) + strlen(rs_data_header[i]); // 寻找前导字符串
    dataEnd = info.find(rs_data_unit[i], dataStart);                      // 寻找单位字符串
    if(dataEnd != string::npos)
    {
        dataStr = info.substr(dataStart, dataEnd - dataStart);
        strcpy(res_data.cpu_name, dataStr.c_str());
    }

    dataStart = info.find(rs_data_header[i + 1]) + strlen(rs_data_header[i + 1]); // 寻找前导字符串
    dataEnd = info.find(rs_data_unit[i + 1], dataStart);                      // 寻找单位字符串
    if(dataEnd != string::npos)
    {
        dataStr = info.substr(dataStart, dataEnd - dataStart);
        strcpy(res_data.gpu_name, dataStr.c_str());
    }

    // 装载数据
    res_data.cpu_usage = data[0] / 10; // CPU利用率
    res_data.cpu_temp = data[1] / 10;       // CPU温度
    res_data.cpu_freq = data[2] / 10;  // CPU主频
    res_data.cpu_power = data[3];      // CPU功耗(扩大10倍)

    res_data.gpu_usage = data[4] / 10; // GPU利用率
    res_data.gpu_temp = data[5] / 10;       // GPU温度
    res_data.gpu_freq = data[6] / 10;//GPU核心频率
    res_data.gpu_power = data[7];      // GPU功耗(扩大10倍)
    res_data.ram_usage = data[8] / 10; // RAM使用率
    res_data.ram_used = data[9] / 10;   // RAM使用量

    res_data.net_upload_speed = data[10];    // net上行速率
    res_data.net_download_speed = data[11]; // net下行速率

    res_data.gpu_ram_used = data[12] / 10;       //GPU内存使用量
    res_data.gpu_ram_usage = data[13] / 10;     //GPU内存使用率
    res_data.disk_temp = data[14] / 10;                 //硬盘温度
    res_data.disk_usage = data[15] / 10;                //硬盘使用率
    res_data.cpu_fan_speed = data[16] / 10;         //CPU风扇转速
    res_data.gpu_fan_speed = data[17] / 10;         //GPU风扇转速

    res_data.hour = data[18] / 10;          //时
    res_data.min = data[19] / 10;           //分
    res_data.year = data[20] / 10;          //年
    res_data.month = data[21] / 10;         //月
    res_data.date = data[22] / 10;          //日

    return res_data;
}

static int thread_func(PCResource *obj)
{
    usleep(50000);
    string info = "null";
    PCResInfo res_info;

    while (!obj->getExitFlag())
    {
        int ret = obj->GetData(info);
        if (ret == 0)
        {
            res_info = obj->AnalyticData(info);

            obj->getUIMutex()->lock();
            pc_resource_gui_update_data(&res_info);
            obj->getUIMutex()->unlock();
        }
        
        sleep(1);
    }

    return 0;
}
